﻿package com.nicoB.tetris {
	import com.nicoB.tetris.constants.ActionsType;
	import com.nicoB.tetris.constants.Blocks;
	import com.nicoB.tetris.events.TetrisEvent;
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.utils.Timer;		

	/**
	 * @author n.bush
	 * @project tetris
	 * @date 5 nov. 2008
	 * @desc 
	 */
	public class Tetris extends Sprite {
		
		private var _renderer : Renderer;
		private var _engine : Engine;
		private var _keyboardManager : KeyboardManager;

		private var _nextBlockType : String;		
		
		private var _timer : Timer;
		
		private var _level : uint;
		private var _lines : uint;
		private var _score : uint;
		private var _linesByLevel : uint;
		
		private var _speedByLevel : Array = [500, 400, 300, 200, 100, 50, 10, 1];
		
		
		
		public var scorePannel : ScorePannel;

		
		
		public function Tetris() {
			
			_renderer = new Renderer(25);
			_renderer.addEventListener(TetrisEvent.LINES_REMOVED, _onLinesRemoved, false, 0, true);
			addChildAt(_renderer, 0);
			
			_engine = new Engine(20, 10);
			_engine.addEventListener(TetrisEvent.BLOCK_POSITIONNED, _onBlockPositionned, false, 0, true);
			_engine.addEventListener(TetrisEvent.GAME_OVER, _onGameOver, false, 0, true);
			_engine.addEventListener(TetrisEvent.LINE_FILLED, _onLineFilled, false, 0, true);
			
			
			scorePannel.blockWidth = 25;
			
						
			_buildKeyboard();
			_buildSteps();
			
			addEventListener(Event.ENTER_FRAME, _draw, false, 0, true);
			
			_onBlockPositionned();
			_keyboardManager.start();
			
		}
		
		
		private function _onBlockPositionned(e : TetrisEvent = null):void{
			
			//si aucun futur block n'est defini, on le fait
			if (_nextBlockType == null)
				_nextBlockType = _getRandomBlock();
			
			_engine.addBlock(_nextBlockType);
			
			//on specifie quel sera le prochain block
			_nextBlockType = _getRandomBlock();
			scorePannel.showNextBlock(_nextBlockType);
			
		}
		
		private function _getRandomBlock() : String {
			var blocksType : Array = [Blocks.L, Blocks.LINE, Blocks.S, Blocks.SQUARE, Blocks.T];
			var block : String = blocksType[Math.floor(Math.random() * blocksType.length)];
			return block;
			
		}

		
		
		
		
		private function _onGameOver(e : TetrisEvent):void{
			_engine.clear();
			scorePannel.score = 0;
			scorePannel.level = 0;
			scorePannel.lines = 0;
			
			_level = 0;
			_score = 0;
			_lines = 0;
			_linesByLevel = 0;
			
			_updateSpeed();
		}

		
		private function _onLineFilled(e : TetrisEvent):void {
			
			_draw();
			
			//mise a jour du score
			_score = (_score + (_level + 1) * 100 * e.linesToRemove.length);
			scorePannel.score = _score;
			
			//mise a jour du niveau
			_linesByLevel += e.linesToRemove.length;
			_lines += e.linesToRemove.length;
			scorePannel.lines = _lines;
			
			if (_linesByLevel >= 10) {
				_level++;
				
				scorePannel.level = _level;
				
				_linesByLevel = 0;
				_updateSpeed();
			}
			
			
			//on arrete le renderer
			_timer.stop();
			
			//on retire les lignes		
			_renderer.removeLines(e.linesToRemove);
			
			
			
			_keyboardManager.stop();
			
		}
		
		
		private function _onLinesRemoved(e : TetrisEvent) : void {
			
			
			_timer.start();
			
			_engine.removeFullLines();
			_onBlockPositionned();
			_keyboardManager.start();
			
		}
		
		

		
		//--------------------------------------
		//					SPEED
		//--------------------------------------
		
		private function _buildSteps():void{
			_timer = new Timer(_speedByLevel[0]);
			_timer.addEventListener(TimerEvent.TIMER, _onStep, false, 0, true);
			_timer.start();
		}
		
		private function _updateSpeed() : void {
			_timer.delay = _speedByLevel[_level];
		}

		
		
		
		
		private function _onStep(e : TimerEvent) : void {
			_engine.step();
		}

		
		//--------------------------------------
		//					KEYBOARD
		//--------------------------------------
		
		private function _buildKeyboard():void{
			_keyboardManager = new KeyboardManager(stage);
			_keyboardManager.addEventListener(TetrisEvent.CLIENT_ACTION, _onAction, false, 0, true);
		}

		
		private function _onAction(e : TetrisEvent) : void {
			switch (e.action){
				case ActionsType.MOVE_LEFT:
					_engine.moveBlockX(-1);
					break;
				case ActionsType.MOVE_RIGHT:
					_engine.moveBlockX(1);
					break;
				case ActionsType.MOVE_DOWN:
					_engine.moveDown();
					break;
				case ActionsType.ROTATE_BLOCK:
					_engine.rotateBlock(1);
					break;
				
			}
		}

		//--------------------------------------
		//					DRAW
		//--------------------------------------
		
		private function _draw(e : Event = null):void{
			_renderer.draw(_engine.cells);
		}
		
	}
}
